package com.bilibili.server.service;

import cn.hutool.core.collection.CollectionUtil;
import com.bilibili.autoconfig.template.FaceTemplate;
import com.bilibili.autoconfig.template.OssTemplate;
import com.bilibili.autoconfig.template.TXSMSTemplate;
import com.bilibili.commons.Constants;
import com.bilibili.commons.exception.TanHuaException;
import com.bilibili.dubbo.api.db.UserApi;
import com.bilibili.dubbo.api.db.UserInfoApi;
import com.bilibili.dubbo.api.mongo.UserLikeApi;
import com.bilibili.model.db.User;
import com.bilibili.model.db.UserInfo;
import com.bilibili.model.mongo.UserLike;
import com.bilibili.model.vo.*;
import com.bilibili.server.interceptor.UserHolder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.joda.time.DateTime;
import org.joda.time.Years;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author HuangRongFu
 * 2021/11/17 星期三9:17 上午
 */

@Service
@Slf4j
public class UserInfoService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private FaceTemplate faceTemplate;

    @Autowired
    private OssTemplate ossTemplate;

    @Autowired
    private TXSMSTemplate txsmsTemplate;

    @Autowired
    private MovementService movementService;

    @Autowired
    private UserService userService;

    @DubboReference
    private UserInfoApi userInfoApi;

    @DubboReference
    private UserApi userApi;

    @DubboReference
    private UserLikeApi userLikeApi;

    /**
     * 完善个人信息
     *
     * @param userInfoVo
     */
    public void loginReginfo(UserInfoVo userInfoVo) {

        //取出token  获取到用户的信息  并且验证用户登陆是否失效
//        User loginUser = getLoginUserByToken(token);

        UserInfo userInfo = new UserInfo();
        //因为userInfoVo是用来和前端交互的对象  后台操作时要使用userInfo
        // 所以要将userInfoVo中的数据复制给userInfo
        BeanUtils.copyProperties(userInfoVo, userInfo);

        //要给userInfo设置id  年龄
        userInfo.setId(UserHolder.getUserId());
        userInfo.setAge(getAge(userInfoVo.getBirthday()));

        //最后使用userInfoApi 将用户信息存入到数据库
        userInfoApi.add(userInfo);
    }

    /**
     * 通过token获取redis中的登录用户信息
     *
     * @params: token
     * @Return: User
     */
    /*  通过UserHolder 同意处理了token所以不再需要拼接方法
    private User getLoginUserByToken(String token) {

        //拼接token 从redis中获取loginUser信息
        String key = "TOKEN_" + token;

        String loginUserJsonString = stringRedisTemplate.opsForValue().get(key);

        //如果用户信息为空 则需要用户重新登录
        if (StringUtils.isEmpty(loginUserJsonString)) {

            throw new TanHuaException("登录超时,请重新登录!");
        }

        //如果有值,就把jsonString转为java对象User
        return JSON.parseObject(loginUserJsonString, User.class);
    }
     */

    /**
     * 通过年-月-日 获取用户年龄
     *
     * @params: yearMonthDay
     * @Return: int
     */
    private int getAge(String yearMonthDay) {

        try {
            //日期转换
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

            //将string的生日 转化为 Date类型
            Date birthday = sdf.parse(yearMonthDay);

            //比较两个年之间的差值
            Years years = Years.yearsBetween(new DateTime(birthday), DateTime.now());

            return years.getYears();
        } catch (ParseException e) {

            log.error("获取用户年龄失败", e);
            return 0;
        }
    }

    /**
     * 用户头像上传
     *
     * @params: headPhoto
     * @params: token
     */
    public void uploadAvatar(MultipartFile headPhoto) {

        //从token中获取登录用户id  校验token是否有效
//        User loginUser = getLoginUserByToken(token);

        try {
            //人脸识别不成功 取反  就抛出异常  提示人脸认证不成功
            if (!faceTemplate.detect(headPhoto.getBytes())) {

                throw new TanHuaException(ErrorResult.faceError());
            }

            //认证成功就将头像文件上传 存储在oss中
            String avatarUrl = ossTemplate.upload(headPhoto.getOriginalFilename(), headPhoto.getInputStream());

            //创建新对象 存入头像
            UserInfo userInfo = new UserInfo();

            userInfo.setAvatar(avatarUrl);
            userInfo.setId(UserHolder.getUserId());

            userInfoApi.update(userInfo);
        } catch (IOException e) {

            log.error("上传头像失败", e);
            throw new TanHuaException("上传头像失败");
        }
    }

    /**
     * 查询用户详细信息
     *
     * @params: userID
     * @params: huanxinID
     * @params: token
     * @Return: UserInfoVo
     */
    public UserInfoVo getUserInfo(Long userID, Long huanxinID) {

        //获取token 校验
//        User loginUser = getLoginUserByToken(token);

        //获取要查询的id
        Long userId = UserHolder.getUserId();

        //选择要查询的id  如果userID 和 huanxinID 都是空 则用token中loginUser的id查询
        if (null != userID) {

            userId = userID;
        }
        if (null != huanxinID) {

            userId = huanxinID;
        }
        //调用api查询用户信息
        UserInfo pojo = userInfoApi.findById(userId);

        //new 一个 UserInfoVo 用来接收要复制的数据
        UserInfoVo vo = new UserInfoVo();

        //复制属性
        BeanUtils.copyProperties(pojo, vo);

        //设置年龄
        vo.setAge(pojo.getAge().toString());

        return vo;
    }

    /**
     * 更新用户信息
     *
     * @params: userInfoVo
     */
    public void updateUserInfo(UserInfoVo vo) {

        //校验token
//        User loginUser = getLoginUserByToken(token);

        Long loginUserId = UserHolder.getUserId();

        UserInfo pojo = new UserInfo();

        //vo 转成 pojo
        BeanUtils.copyProperties(vo, pojo);

        //设置用户年龄 和 id
        pojo.setAge(getAge(vo.getBirthday()));
        pojo.setId(loginUserId);

        userInfoApi.update(pojo);
    }

    /**
     * 更换头像
     *
     * @param headPhoto
     */
    public void updateHeader(MultipartFile headPhoto) {

        uploadAvatar(headPhoto);
    }

    /**
     * 修改手机号-发送验证码
     */
    public void sendVerificationCode() {

        String phone = UserHolder.getUser().getMobile();

        //1. 把验证码存入redis中
        String key = "VALIDATE_CODE_" + phone;

        //2. 有值
        String codeInRedis = stringRedisTemplate.opsForValue().get(key);
        log.info("redis中的验证码有{},{}", phone, codeInRedis);

        // 2.1 验证码未失效，注意查收
        if (StringUtils.isNotEmpty(codeInRedis)) {

            throw new TanHuaException(ErrorResult.duplicate());
        }

        // 3. 没值
        // 3.1 生成验证码
        //String validateCode = RandomStringUtils.randomNumeric(6);

        // 3.2 发送验证码
        String validateCode = "654321";

        //txsmsTemplate.sendValidateCode(phone,validateCode);
        // 3.3 存入redis 设置有效期为5分钟
        stringRedisTemplate.opsForValue().set(key, validateCode, 5, TimeUnit.MINUTES);

        log.info("发送的验证码:{}", validateCode);
    }

    /**
     * 修改手机号-校验验证码
     *
     * @param paramMap
     * @Return: Boolean
     */
    public Map<String, Boolean> checkVerificationCode(Map<String, String> paramMap) {

        //1.取出手机号码
        String phone = UserHolder.getUser().getMobile();

        //2.拼接key(必须与存入时的key一致)
        String key = "VALIDATE_CODE_" + phone;

        String verificationCode = paramMap.get("verificationCode");

        userService.check(phone, verificationCode, key);

        Map<String, Boolean> resultMap = new HashMap<>();
        resultMap.put("verification", true);

        return resultMap;
    }

    /**
     * 修改手机号-保存
     *
     * @param paramMap
     */
    public void updatePhoneNumber(Map<String, String> paramMap) {

        String phone = paramMap.get("phone");

        //判断手机号码格式是否正确
        if (!phone.matches("[1][0-9]{10}")) {

            throw new TanHuaException(Constants.PHONE_ERROR);
        }

        User userInDb = userApi.findByPhone(phone);

        if (null != userInDb) {

            throw new TanHuaException("输入的手机号已注册");
        }

        User user = new User();

        user.setId(UserHolder.getUserId());
        user.setMobile(phone);

        userApi.update(user);
    }

    /**
     * 互相喜欢、喜欢、粉丝、谁看过我 - 翻页列表
     *
     * @param type
     * @param page
     * @param pageSize
     * @return
     */
    public PageResult<UserInfoVoLike> findFriends(Integer type, Long page, Long pageSize) {

        //登录用户id
        final Long userId = UserHolder.getUserId();

        PageResult<UserInfoVoLike> pageResult = new PageResult<>();
        //相互喜欢
        if (type == 1){

            //获取相互喜欢的用户id
            List<Long> likeUSerIds = userLikeApi.findLikeUserIds(userId);

            //通过互相喜欢用户id  查询用户详细信息
            pageResult = userInfoApi.findFansPage(page, pageSize, likeUSerIds, type);

        }else if (type == 2){
            //喜欢用户id
            List<Long> likeUserIds = userLikeApi.findLikeUser(userId);

            pageResult = userInfoApi.findFansPage( page, pageSize, likeUserIds, type);

        }else if (type == 3){

            List<Long> ids= userLikeApi.findFans(userId);

            pageResult = userInfoApi.findFansPage( page, pageSize, ids, type);

            List<UserInfoVoLike> voList = pageResult.getItems();

            voList = userLikeApi.findAlreadyLove(voList, userId);

            pageResult.setItems(voList);

        }else {

            List<VisitorsVo> visitorsVoList = movementService.queryVisitorsList();

            if (CollectionUtil.isNotEmpty(visitorsVoList)){

                List<Long> ids = visitorsVoList.stream().map(VisitorsVo::getId).collect(Collectors.toList());

                pageResult = userInfoApi.findFansPage(page, pageSize, ids, type);

            }else {

                pageResult = null;
            }
        }

        return pageResult;
    }
}
